package br.com.admGearman.seguranca.negocio;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.transform.ResultTransformer;

import br.com.admGearman.seguranca.vo.ExtensaoUsuarioVo;
import br.com.admGearman.seguranca.vo.UsuarioVo;
import br.com.admGearman.util.hibernate.business.HibernateUtil;
import br.com.r2.exception.R2Exception;
import br.com.r2.util.Criptografia;
import br.com.r2.util.hibernate.business.NegocioThrow;
import br.com.r2.util.hibernate.business.R2HbNgc;
import br.com.r2.util.hibernate.business.RestritorHb;
import br.com.r2.util.tipodado.Flag;
import br.com.r2.util.tipodado.YesNo;

@SuppressWarnings("unchecked")
public class UsuarioNgc extends R2HbNgc<UsuarioVo>
{
   
   private Map filtroPropriedade = new HashMap();

   private Map restritores = new HashMap();

   private static UsuarioNgc instancia = null;

   public static final int JOIN_USUARIOINCLUSAO = 1;

   public static final int JOIN_USUARIOALTERACAO = 2;

   public static final int JOIN_EST_EMPRESA = 4;

   public static final int JOIN_EXTENSAO_USUARIO = 8;

   public static final int JOIN_EXTENSAO_USUARIO_ESTLOJA = 16;

   public static String SENHA_PADRAO = "1234";
   
   private UsuarioNgc()
   {
      init(restritores, filtroPropriedade, UsuarioVo.class);
      addFiltro("login", RestritorHb.RESTRITOR_EQ, "login");
      addFiltro("nome", RestritorHb.RESTRITOR_LIKE, "nome");
      addFiltro("flagAtivo", RestritorHb.RESTRITOR_EQ, "flagAtivo");
      addFiltro("estEmpresa.codigo", RestritorHb.RESTRITOR_EQ, "estEmpresaVo.codigo");
      addFiltro("estEmpresa.cnpj", RestritorHb.RESTRITOR_EQ, "estEmpresaVo.cnpj");
      addFiltro("estloja", RestritorHb.RESTRITOR_IN, "filtro.listaEstLojas");
   }

   public static UsuarioNgc getInstancia()
   {
      if (instancia == null)
      {
         instancia = new UsuarioNgc();
      }
      return instancia;
   }

   @Override
   protected Map filtroPropriedade()
   {
      return filtroPropriedade;
   }

   @Override
   protected Criteria montaCriteria(Session sessao, int join)
   {
      Criteria criteria = sessao.createCriteria(UsuarioVo.class);
      if ((join & JOIN_USUARIOINCLUSAO) != 0)
      {
         criteria.createCriteria("usuarioInclusaoVo", "usuarioInclusao", Criteria.INNER_JOIN);
      }
      if ((join & JOIN_USUARIOALTERACAO) != 0)
      {
         criteria.createCriteria("usuarioAlteracaoVo", "usuarioAlteracao", Criteria.LEFT_JOIN);
      }
      if ((join & JOIN_EST_EMPRESA) != 0)
      {
         criteria.createCriteria("estEmpresaVo", "estEmpresa", Criteria.INNER_JOIN);
      }
      if ((join & JOIN_EXTENSAO_USUARIO) != 0)
      {
         criteria.createCriteria("listaExtensaoUsuarioVo", "extensaoUsuario", Criteria.LEFT_JOIN);
         if ((join & JOIN_EXTENSAO_USUARIO_ESTLOJA) != 0)
         {
            criteria.createCriteria("extensaoUsuario.estLojaVo", "estLoja", Criteria.LEFT_JOIN);
         }
      }
      
      return criteria;
   }

   @Override
   protected void setarOrdenacao(Criteria criteria, UsuarioVo filter, int join)
   {
      criteria.addOrder(Order.desc("flagAtivo"));
      criteria.addOrder(Order.asc("nome"));
   }
   
   @Override
   protected Map restritores()
   {
      return restritores;
   }

   public void alterarSenha(UsuarioVo usuarioVo) throws R2Exception
   {
      Session sessao = HibernateUtil.getSession();
      sessao.setFlushMode(FlushMode.COMMIT);
      Transaction tx = sessao.beginTransaction();
      try
      {

         this.alterarSenha(sessao, usuarioVo);
         tx.commit();

      }
      catch (Exception e)
      {
         throw NegocioThrow.getInstancia().catchHBEdicaoSession(e, tx);
      }
      finally
      {
         sessao.close();
      }
   }

   private void alterarSenha(Session sessao, UsuarioVo usuarioVo) throws R2Exception
   {
      validarAlterarSenha(sessao, usuarioVo);

      try
      {
         UsuarioVo vo = new UsuarioVo();
         vo.setCodigo(usuarioVo.getCodigo());

         vo = this.get(sessao, vo, 0);

         String senhaCriptografada = Criptografia.criptografar(usuarioVo.getSenha());
         vo.setSenha(senhaCriptografada);

         sessao.merge(vo);
      }
      catch (Exception e)
      {
         throw new R2Exception("erro.encriptar.senha");
      }
   }

   private void validarAlterarSenha(Session sessao, UsuarioVo usuarioVo) throws R2Exception
   {
      if (usuarioVo == null)
      {
         throw new R2Exception("campo.obrigatorio", new String[] { "lbl_usuario" });
      }
      if (usuarioVo.getCodigo() == null || !usuarioVo.getCodigo().isPreenchido())
      {
         throw new R2Exception("campo.obrigatorio", new String[] { "lbl_id" });
      }
      if (usuarioVo.getSenhaAtual() == null || usuarioVo.getSenhaAtual().trim().equals(""))
      {
         throw new R2Exception("campo.obrigatorio", new String[] { "lbl_senha_atual" });
      }
      if (usuarioVo.getSenha() == null || usuarioVo.getSenha().trim().equals(""))
      {
         throw new R2Exception("campo.obrigatorio", new String[] { "lbl_senha" });
      }
      if (usuarioVo.getConfirmacaoSenha() == null || usuarioVo.getConfirmacaoSenha().trim().equals(""))
      {
         throw new R2Exception("campo.obrigatorio", new String[] { "lbl_confirmacao_senha" });
      }
      if (!usuarioVo.getSenha().equals(usuarioVo.getConfirmacaoSenha()))
      {
         throw new R2Exception("senha.diferente.confirmacaoSenha");
      }

      UsuarioVo vo = new UsuarioVo();
      try
      {
         vo.setCodigo(usuarioVo.getCodigo());

         vo = UsuarioNgc.getInstancia().get(sessao, vo, 0);
      }
      catch (Exception e)
      {
         throw new R2Exception(e);
      }

      String senhaCriptografada = Criptografia.criptografar(usuarioVo.getSenhaAtual());
      if (!senhaCriptografada.equals(vo.getSenha()))
      {
         throw new R2Exception("senha.incorreta");
      }
   }
   
   @Override
   protected void validarInserir(Session sessao, UsuarioVo vo) throws R2Exception
   {
      validar(sessao, vo);
      
      String senhaCriptografada = Criptografia.criptografar(SENHA_PADRAO);
      vo.setSenha(senhaCriptografada);
      vo.setFlagAlterarSenha(new Flag(YesNo.YES));
   }
   
   @Override
   protected void validarAlterar(Session sessao, UsuarioVo vo) throws R2Exception
   {
      validar(sessao, vo);
      
      if (vo.getCodigo() == null || vo.getCodigo().getValor() <= 0)
      {
         throw new R2Exception("campo.obrigatorio", new String[] { "lbl_codigo" });
      }
   }

   protected void validar(Session sessao, UsuarioVo vo) throws R2Exception
   {
      if (vo == null)
      {
         throw new R2Exception("campo.obrigatorio", new String[] { "lbl_usuario" });
      }
      if (vo.getNome() == null || vo.getNome().getValor() == null || vo.getNome().getValor().trim().equals(""))
      {
         throw new R2Exception("campo.obrigatorio", new String[] { "lbl_nome" });
      }
      if (vo.getLogin() == null || vo.getLogin().getValor() == null || vo.getLogin().getValor().trim().equals(""))
      {
         throw new R2Exception("campo.obrigatorio", new String[] { "lbl_login" });
      }
      /*
      if (vo.getSenha() == null || vo.getSenha().trim().equals(""))
      {
         throw new R2Exception("campo.obrigatorio", new String[] { "lbl_senha" });
      }
      */
      if (vo.getEstEmpresaVo() == null || vo.getEstEmpresaVo().getCodigo() == null || !vo.getEstEmpresaVo().getCodigo().isPreenchido())
      {
         throw new R2Exception("campo.obrigatorio", new String[] { "lbl_empresa" });
      }
      /*  TODO validar a inclusao da extensao do usuario
      if (vo.getListaExtensaoUsuarioVo() != null && vo.getListaExtensaoUsuarioVo().size() > 0)
      {
         Iterator<ExtensaoUsuarioVo> iterator = vo.getListaExtensaoUsuarioVo().iterator();
         while (iterator.hasNext())
         {
            ExtensaoUsuarioVo element = (ExtensaoUsuarioVo) iterator.next();
            
            throw new R2Exception("campo.obrigatorio", new String[] { "lbl_empresa" });
         }
      }
      */
      
      // validando se ja existe esse login para esta empresa
      UsuarioVo filtroVo = new UsuarioVo();
      filtroVo.setEstEmpresaVo(vo.getEstEmpresaVo());
      filtroVo.setLogin(vo.getLogin());
      UsuarioVo retornoVo = null;
      try
      {
         retornoVo = this.get(sessao, filtroVo, JOIN_EST_EMPRESA);
      }
      catch (Exception e)
      {
         throw new R2Exception("erro_inesperado");
      }
      
      if (retornoVo != null && !retornoVo.getCodigo().equals(vo.getCodigo()))
      {
         throw new R2Exception("login_existente");
      }
   }

   @Override
   public UsuarioVo inserir(Session sessao, UsuarioVo vo) throws R2Exception
   {
      validarInserir(sessao, vo);
      try
      {
         // gravando o usuario
         sessao.save(vo);
         
         // gravando a extensao de usuario
         setarExtensaoUsuario(sessao, vo);
      }
      catch (Exception e)
      {
         e.printStackTrace();
         throw new R2Exception("erro_inesperado");
      }
      return vo;
   }
   
   @Override
   public UsuarioVo alterar(Session sessao, UsuarioVo vo) throws R2Exception
   {
      validarAlterar(sessao, vo);
      
      sessao.merge(vo);
      
      // gravando a extensao de usuario
      setarExtensaoUsuario(sessao, vo);
      
      return vo;
   }

   private void setarExtensaoUsuario(Session sessao, UsuarioVo vo) throws R2Exception
   {
      if (vo.getFiltroVo() != null
          && vo.getFiltroVo().getListaExtensaoUsuario() != null
          && vo.getFiltroVo().getListaExtensaoUsuario().size() > 0)
      {
         Iterator<ExtensaoUsuarioVo> iterator = vo.getFiltroVo().getListaExtensaoUsuario().iterator();
         while (iterator.hasNext())
         {
            ExtensaoUsuarioVo element = (ExtensaoUsuarioVo) iterator.next();
            if (element.getUsuarioVo() == null
                || element.getUsuarioVo().getCodigo() == null
                || !element.getUsuarioVo().getCodigo().isPreenchido())
            {
               element.setUsuarioVo(vo);
            }
            if (element.getCodigo() == null || !element.getCodigo().isPreenchido())
            {
               // INSERIR
               ExtensaoUsuarioNgc.getInstancia().inserir(sessao, element);
            }
            else
            {
               // ALTERAR
               ExtensaoUsuarioNgc.getInstancia().alterar(sessao, element);
            }
         }
      }
   }

   public List<UsuarioVo> pesquisarResultTransformed(UsuarioVo vo, int join, ResultTransformer resultTransformer) throws R2Exception
   {
      Session sessao = HibernateUtil.getSession();
      sessao.setFlushMode(FlushMode.COMMIT);
      try
      {
         return pesquisarResultTransformed(sessao, vo, join, resultTransformer);
      }
      catch (Exception e)
      {
         throw NegocioThrow.getInstancia().catchHBConsultaSession(e);
      }
      finally
      {
         sessao.close();
      }
   }

   public List<UsuarioVo> pesquisarResultTransformed(Session sessao, UsuarioVo vo, int join, ResultTransformer resultTransformer) throws Exception
   {
      
      this.addFiltroValidacao(sessao, vo);

      Criteria criteria = this.montaCriteria(sessao, join);

      this.setarOrdenacao(criteria, vo, join);

      this.restringir(criteria, vo);
      
      this.setNumeroMaximoRegistros(sessao, criteria, vo, join);

      criteria.setResultTransformer(resultTransformer);
      
      return criteria.list();
   }
   
}
